package com.designoutput.ui
{
	import com.designoutput.elements.Base;
	import com.designoutput.elements.BaseElement;
	import com.designoutput.elements.BaseRectElement;
	import com.designoutput.elements.EllipseElement;
	import com.designoutput.elements.ImageElement;
	import com.designoutput.elements.LineElement;
	import com.designoutput.elements.PolyLineElement;
	import com.designoutput.elements.RectElement;
	import com.designoutput.elements.RoundRectElement;
	import com.designoutput.elements.StarElement;
	import com.designoutput.elements.TextElement;
	import com.designoutput.enum.Direction;
	import com.designoutput.enum.ElementType;
	import com.designoutput.enum.ToolType;
	import com.designoutput.event.CardEditorEvent;
	import com.designoutput.event.CardEvent;
	import com.designoutput.event.CardLayerEvent;
	import com.designoutput.event.NumberEvent;
	import com.designoutput.event.RulerEvent;
	import com.designoutput.event.ScrollEvent;
	import com.designoutput.manager.ClipboardManager;
	import com.designoutput.ui.controls.Literal;
	import com.designoutput.ui.controls.NumberInput;
	import com.designoutput.ui.controls.Ruler;
	import com.designoutput.ui.editors.BaseEditor;
	import com.designoutput.ui.editors.TransformEditor;
	import com.designoutput.ui.editors.transformEditorClasses.TransformBoxEvent;
	import com.designoutput.ui.newControls.Scrollbar;
	import com.designoutput.utils.Globals;
	import com.designoutput.utils.HitTestUtils;
	import com.designoutput.utils.SnapUtils;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.ui.Keyboard;
	
	public class CardFaceEditor extends Base
	{		
		private var mouseDown:Boolean = false;
		private var mouseOver:Boolean = false;
		
		private var _binfo:Sprite;
		private var _hscroll:Scrollbar;
		private var _vscroll:Scrollbar;
		private var _cardSizeInfor:CardFaceEditorSizeInfo;
		private var _content:Sprite;
		private var _zoomNumberInput:NumberInput;
		
		public var zoomlevel:Number = 1;
		
		private var _invalidScroll:Boolean = false;
		
		private var _ruler:Ruler;
		private var _layerHolder:Sprite;
		private var _card:Card;
		public var layer:CardFace;
		
		private var _active:Boolean = false;
		
		private var _transformBox:TransformEditor;
		private var _currentEditor:BaseEditor;
				
		private var _drawingPoints:Array; // used to store new added poly line points		
		public var currentToolType:String = ToolType.None;
		private var _lastX:Number;
		private var _lastY:Number;
		
		public function CardFaceEditor(card:Card):void {
			_card = card;
			
			_card.addEventListener(CardEvent.CARD_TYPE_CHANGED, layer_typeChangedHandler, false, 0, true);
			_card.addEventListener(CardEvent.UNIT_CHANGED, layer_unitChangedHandler, false, 0, true);
		}
		
		override protected function initialize():void
		{
			super.initialize();
			
			_content = new Sprite();
			addChild(_content);
			
			_binfo = new Sprite();
			_binfo.graphics.beginFill(0xD8D8D9);
			_binfo.graphics.drawRect(0, 0, 40, 16);
			_binfo.graphics.beginFill(0xFFFFFF);
			_binfo.graphics.drawRect(0, 0, 40, 16);
			_binfo.graphics.endFill();
			
			_zoomNumberInput = new NumberInput(28, 100, 5, 800, false, true);
			_zoomNumberInput.border = false;
			_zoomNumberInput.background = false;
			_zoomNumberInput.addEventListener(NumberEvent.VALUE_CHANGE, ztb_valueChangedHandler);
			_binfo.addChild(_zoomNumberInput);
			
			var _lit:Literal = new Literal("%");
			_lit.x = 25;
			_lit.y = -2;
			_binfo.addChild(_lit);
			addChild(_binfo);
			
			_cardSizeInfor = new CardFaceEditorSizeInfo();
			addChild(_cardSizeInfor);			
			
			_vscroll = new Scrollbar(Direction.Vertical);
			_vscroll.addEventListener(ScrollEvent.SCROLL, this.verticalScroll, false, 0, true);
			addChild(_vscroll);
			
			_hscroll = new Scrollbar(Direction.Horizontal);
			_hscroll.addEventListener(ScrollEvent.SCROLL, this.horizontalScroll, false, 0, true);
			addChild(_hscroll);
			
			_transformBox = new TransformEditor();
			_transformBox.x = 20;
			_transformBox.y = 20;
			_transformBox.addEventListener(TransformBoxEvent.TRANSFORMED, editor_transformedHandler, false, 0, true);
			
			_layerHolder = new Sprite();
			_layerHolder.x = 20;
			_layerHolder.y = 20;
			_layerHolder.mouseChildren = false;
			_layerHolder.doubleClickEnabled = true;
			_layerHolder.graphics.beginFill(0, 0);
			_layerHolder.graphics.drawRect(-2000, -2000, 4000, 4000);
			_content.addChild(_layerHolder);
			
			_ruler = new Ruler(this);
			_content.addChild(_ruler);
			
			applyScroll();
			
			addEventListener(Event.ADDED_TO_STAGE, addedToStage);		
			
			_drawingPoints = [];
			_lastX = 0;
			_lastY = 0;
			
			mouseChildren = false;
		}
		
		public function get viewing():Boolean {
			return visible;
		}
		
		public function set viewing(value:Boolean):void {
			visible = value;
			if(layer)
				layer.viewing = value;
		}
		
		public function setLayer(layer:CardFace):void {
			if(this.layer != null){
				this.layer.viewing = false;
				
				this.layer.removeEventListener(CardLayerEvent.SIZE_CHANGED, card_sizeChangedHandler, false);
				
				if(_layerHolder.contains(this.layer))
					_layerHolder.removeChild(this.layer);
				
				_content.removeChild(_transformBox);
				
				this.layer = null;
			}
			
			this.layer = layer;
			
			if(this.layer != null){
				this.layer.viewing = viewing;
				
				_layerHolder.addChild(this.layer);
				_content.addChild(_transformBox);
				this.layer.addEventListener(CardLayerEvent.SIZE_CHANGED, card_sizeChangedHandler, false, 0, true);
			}
			
			updateCardSizeInfo();
			invalidateDisplay();
		}
		
		public function horizontalScroll(evt:ScrollEvent):void
		{
			_invalidScroll = true;
			invalidateProperties();
		}
		
		public function verticalScroll(evt:ScrollEvent):void
		{
			_invalidScroll = true;
			invalidateProperties();
		}
		
		override protected function commitProperties():void {
			super.commitProperties();
			
			if(_invalidScroll){
				_invalidScroll = false;
				applyScroll();
			}
		}
		
		override protected function updateDisplay():void {
			super.updateDisplay();
			
			var contentAvailableWidth:Number =  _width - _vscroll.width; //ScrollBar
			var contentAvailableHeight:Number = _height - _hscroll.height - (_width < 300 ? 16 : 0); //ScrollBar
			
			graphics.clear();
			if(_active)
				graphics.beginFill(0x999b9e);
			else
				graphics.beginFill(0xb9bbbe);
			graphics.drawRect(0, 0, _width, _height);
			
			var scrollContentSize:Point = getScrollContentSize();
			
			_vscroll.x = _width - _vscroll.width;
			_vscroll.y = 0;
			_vscroll.viewportSize = contentAvailableHeight;
			_vscroll.size = contentAvailableHeight - _vscroll.y;
			_vscroll.contentSize = scrollContentSize.y;
			
			if(_width < 300){ //Botton info in 2 rows
				_hscroll.x = 0;
				_hscroll.y = _height - _hscroll.height - 16;
				_hscroll.viewportSize = contentAvailableWidth;
				_hscroll.size = contentAvailableWidth;
				_hscroll.contentSize = scrollContentSize.x;
				
				_binfo.x = 0;
				_binfo.y = _height - 16;
				
				_cardSizeInfor.x = 40;
				_cardSizeInfor.y = _height - 16;
				_cardSizeInfor.width = contentAvailableWidth - _cardSizeInfor.x;
			} else {
				_hscroll.x = 190;
				_hscroll.y = _height - _hscroll.height;
				_hscroll.viewportSize = contentAvailableWidth;
				_hscroll.size = contentAvailableWidth - _hscroll.x;
				_hscroll.contentSize = scrollContentSize.x;
				
				_binfo.x = 0;
				_binfo.y = _hscroll.y;
				
				_cardSizeInfor.x = 40;
				_cardSizeInfor.y = _hscroll.y;
				_cardSizeInfor.width = 150;
			}
			
			applyScroll();
			
			_ruler.setParameters(Math.max(contentAvailableWidth, scrollContentSize.x), Math.max(contentAvailableHeight, scrollContentSize.y));
		}
		
		protected function applyScroll():void {	
			var rect:Rectangle = _content.scrollRect || new Rectangle();
			
			rect.x = _hscroll.scrollAmount;
			rect.y = _vscroll.scrollAmount;
			
			rect.width = _hscroll.viewportSize;
			rect.height = _vscroll.viewportSize;
			
			_content.scrollRect = rect;			
		}
		
		/**
		 * Just show "T-Shirts"  when card type is it. 
		 */		
		public function showTShirtInfor():void{
			_cardSizeInfor.text = "T-Shirts";
		}
		
		private function ruler_unitChangeHandler(evt:RulerEvent):void
		{
			_card.changeUnit(evt.unit);
		}
		
		private function layer_unitChangedHandler(e:Event):void {
			_ruler.setUnit(_card.unit);
			updateCardSizeInfo();
		}
		
		
		protected function card_sizeChangedHandler(e:Event):void {
			updateCardSizeInfo();
			invalidateDisplay();
		}
		
		protected function layer_typeChangedHandler(e:Event):void {
			updateCardSizeInfo();
			invalidateDisplay();
		}
		
		protected function updateCardSizeInfo():void {
			if(layer)
				_cardSizeInfor.text = /*layer.name + " - " +*/ layer.widthInUnit + "x" + layer.heightInUnit + " " + layer.unit.symbol;
			else
				_cardSizeInfor.text = "";
		}
		
		public function showRuler(flag:Boolean):void
		{
			_ruler.visible = flag;
		}
		
		public function get showMargins():Boolean
		{
			return layer.showMargins;
		}
		
		public function set showMargins(value:Boolean):void {
			layer.showMargins = value;
		}
		
		public function activate():void {
			_active = true;
			
			mouseChildren = true;
			
			invalidateDisplay();
			
			_ruler.addEventListener(RulerEvent.UNIT_CHANGE, ruler_unitChangeHandler, false, 0, true);
			
			_layerHolder.addEventListener(MouseEvent.MOUSE_DOWN, layerMouseDown, false, 0, true);
			Globals.designoutputCard.stage.addEventListener(MouseEvent.MOUSE_MOVE, layerMouseMove, false, 0, true);
			_layerHolder.addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler, false, 0, true);
			_layerHolder.addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler, false, 0, true);
			_layerHolder.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler, false, 0, true);
			
			addEventListener(Event.CUT, cutHandler, false, 0, true);
			addEventListener(Event.COPY, copyHandler, false, 0, true);
			addEventListener(Event.PASTE, pasteHandler, false, 0, true);
			
			addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler, false, 0, true);
			addEventListener(KeyboardEvent.KEY_UP, keyUpHandler, false, 0, true);
			
			if(stage){
				Globals.focusManager.setFocus(this);
				Globals.focusManager.defaultFocus = this;
			}
		}
		
		public function deactivate(dispose:Boolean = false):void {
			_active = false;
			
			mouseChildren = false;
			
			invalidateDisplay();
			
			_ruler.removeEventListener(RulerEvent.UNIT_CHANGE, ruler_unitChangeHandler, false);
			
			_layerHolder.removeEventListener(MouseEvent.MOUSE_DOWN, layerMouseDown, false);
			Globals.designoutputCard.stage.removeEventListener(MouseEvent.MOUSE_MOVE, layerMouseMove, false);
			_layerHolder.removeEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler, false);
			_layerHolder.removeEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler, false);
			_layerHolder.removeEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler, false);
			
			removeEventListener(Event.CUT, cutHandler, false);
			removeEventListener(Event.COPY, copyHandler, false);
			removeEventListener(Event.PASTE, pasteHandler, false);
			
			removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler, false);
			removeEventListener(KeyboardEvent.KEY_UP, keyUpHandler, false);
			
			dropSelItems();
		}
			
		public function mouseOverHandler(evt:MouseEvent):void
		{
			mouseOver = true;
			Globals.cursorManager.setCursor(Globals.designoutputCard.tool);
		}
		
		public function mouseOutHandler(evt:MouseEvent):void
		{
			mouseOver = false;
			Globals.cursorManager.setCursor(ToolType.None);
		}
		
		public function ztb_valueChangedHandler(evt:NumberEvent):void
		{
			zoom(evt.value);
		}
		
		protected function getScrollContentSize():Point {
			if(layer == null)
				return new Point(0, 0);
			
			return new Point(layer.width * zoomlevel + _layerHolder.x * 2, layer.height * zoomlevel + _layerHolder.y * 2);
		}
		
		public function zoom(percentNum:int):void
		{			
			if (percentNum > 800)
				percentNum = 800;
			else if (percentNum < 5)
				percentNum = 5;
			
			zoomlevel = percentNum * 0.01;
			
			_zoomNumberInput.text = percentNum.toString();
			
			_layerHolder.scaleX = zoomlevel;
			_layerHolder.scaleY = zoomlevel;
			
			_transformBox.scaleX = zoomlevel;
			_transformBox.scaleY = zoomlevel;
			
			_ruler.setScale(zoomlevel);
			
			invalidateDisplay();
			
			dispatchEvent( new CardEditorEvent(CardEditorEvent.ZOOM_CHANGED) );
		}
		
		private function addedToStage(evt:Event):void
		{
			if(_active){
				Globals.focusManager.setFocus(this);
				Globals.focusManager.defaultFocus = this;
			}
		}
		
		public function getElementFromCursor():BaseElement
		{
			var element:BaseElement = null;
			for(var i:int = layer.numElements - 1; i >= 0; i--){
				var loopElement:BaseElement = layer.getElementAt(i);
				if (loopElement && loopElement.hitTestPoint(stage.mouseX, stage.mouseY, true) && (!element))
					element = loopElement;
			}
			return element;
		}
		
		public function getTypeFromCursor():String
		{
			var strType:String = ToolType.Layer;
			var element:BaseElement = getElementFromCursor();
			if (element){
				if(element is TextElement && (element as TextElement).editable)
					strType =  ToolType.None;
				else
					strType = ToolType.ElementBody;
			}
			return strType;
		}
		
		private function editor_transformedHandler(e:Event):void {
			_card.updateElementsOption();
		}
			
		public function layerMouseDown(evt:MouseEvent):void
		{
			if(layer == null || !_active)
				return;
			
			stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUpHandler);
			
			mouseDown = true;
			
			_lastX = Math.round(layer.mouseX);
			_lastY = Math.round(layer.mouseY);
			
			var element:BaseElement = getElementFromCursor();
			
			if(!(element is TextElement))
				_layerHolder.mouseChildren = false;
			
			var newMode:String = getTypeFromCursor();
			
			switch (currentToolType)
			{
				case ToolType.None:
				case ToolType.Layer:
					if (evt.shiftKey)
					{
						if (element && newMode == ToolType.ElementBody)
						{
							if(element.selected)
								dropSelItem(element);
							else
								addSelItem(element);
						}
					}
					else
					{
						if (!element || !element.selected)
						{
							dropSelItems();
							if (element){
								addSelItem(element);
								_currentEditor.mouseDownOnElement(element);
							}
						} else {
							if(!((element is TextElement) && (element as TextElement).editable))
								_currentEditor.mouseDownOnElement(element);
						}
					}
					break;
				case ToolType.FreeFormLine:
					var point:Point = new Point(layer.mouseX, layer.mouseY);
					if (SnapUtils.snapEnabled && this._drawingPoints.length > 0)
					{
						var nLastPoint:Point = this._drawingPoints[this._drawingPoints.length - 1];
						point = SnapUtils.getSnapLine(nLastPoint.x, nLastPoint.y, layer.wrapX(layer.mouseX), layer.wrapY(layer.mouseY));
					}
					this._drawingPoints.push(new Point(layer.wrapX(point.x), layer.wrapY(point.y)));
					layerMouseMove();
					break;
				default:
					break;
			}
			
			if (currentToolType == ToolType.None)
				setTool(newMode);
			
			_card.updateElementsOption();
		}
		
		public function layerMouseMove(evt:MouseEvent = null):void
		{
			if(layer == null || !_active)
				return;
			
			//
			if (currentToolType == ToolType.FreeFormLine || mouseDown){
				var point:Point = new Point(layer.mouseX, layer.mouseY);
				
				if (SnapUtils.snapEnabled)
					point = SnapUtils.getSnapRect(_lastX, _lastY, layer.wrapX(layer.mouseX), layer.wrapY(layer.mouseY));
				
				switch (currentToolType)
				{
					case ToolType.Layer:
						layer.overlay.graphics.clear();
						drawFrameRect(layer.overlay, layer.wrapX(_lastX), layer.wrapY(_lastY), layer.wrapX(layer.mouseX), layer.wrapY(layer.mouseY), 0);
						break;
					case ToolType.Rectangle:
					case ToolType.Text:
					case ToolType.Image:
						layer.overlay.graphics.clear();
						drawSolidRect(layer.overlay, _lastX, _lastY, point.x, point.y);
						break;
					case ToolType.RoundRectangle:
						layer.overlay.graphics.clear();
						drawRoundRect(layer.overlay, layer.wrapX(_lastX), layer.wrapY(_lastY), layer.wrapX(point.x), layer.wrapY(point.y), 15, 0);
						break;
					case ToolType.Ellipse:
						layer.overlay.graphics.clear();
						drawOvalRect(layer.overlay, layer.wrapX(_lastX), layer.wrapY(_lastY), layer.wrapX(point.x), layer.wrapY(point.y), 0);
						break;
					case ToolType.StarPolygon:
						layer.overlay.graphics.clear();
						drawPolyStar(layer.overlay, _lastX, _lastY, layer.wrapX(point.x), layer.wrapY(point.y), 5, .37);
						break;
					case ToolType.FreeFormLine:
						layer.overlay.graphics.clear();
						if (SnapUtils.snapEnabled && _drawingPoints.length > 0)
						{
							var nLastPoint:Object = _drawingPoints[_drawingPoints.length - 1];
							point = SnapUtils.getSnapLine(nLastPoint.x, nLastPoint.y, layer.mouseX, layer.mouseY);
						}
						if (_drawingPoints.length > 0)
						{
							_drawingPoints.push(new Point(layer.wrapX(point.x), layer.wrapY(point.y)));
							drawPolyLine(layer.overlay, _drawingPoints, 0, 100, 1);
							_drawingPoints.pop();
						}
						break;
					case ToolType.Line:
						if (SnapUtils.snapEnabled)
							point = SnapUtils.getSnapLine(_lastX, _lastY, layer.wrapX(layer.mouseX), layer.wrapY(layer.mouseY));
						layer.overlay.graphics.clear();
						layer.overlay.graphics.lineStyle(1, 0, 100);
						layer.overlay.graphics.moveTo(layer.wrapX(_lastX), layer.wrapY(_lastY));
						layer.overlay.graphics.lineTo(layer.wrapX(point.x), layer.wrapY(point.y));
						break;
					case ToolType.ElementBody:
					case ToolType.None:
					default:
						break;
				}
			}
			//
			
			updateCursor();
		}
		
		
		/**
		 * Get the handle type by the given ToolType when chose the 8 handle for common elements
		 * @param handleType
		 * @return
		 *
		 */
		private function getDiagHandle(handleType:String):String
		{
			switch (handleType)
			{
				case ToolType.HandleTL:
				case ToolType.HandleL:
				case ToolType.HandleT:
					return ToolType.HandleBR;
				case ToolType.HandleTR:
					return ToolType.HandleBL;
				case ToolType.HandleBL:
					return ToolType.HandleTR;
				default:
					return ToolType.HandleTL;
			}
		}
		
		public function doubleClickHandler(evt:MouseEvent):void
		{
			if(layer == null || !_active)
				return;
			
			switch (currentToolType)
			{
				case ToolType.FreeFormLine:
					finalizeMode(true);
					updateCursor();
					break;
				default:
					updateCursor();
					
					if (this.currentToolType == ToolType.None)
					{
						var element:BaseElement = getElementFromCursor();
						if (element)
						{
							switch (element.getClassName())
							{
								case ElementType.TextElement:
									var textElement:TextElement = element as TextElement;
									textElement.editable = true;
									_layerHolder.mouseChildren = true;
									break;
								case ElementType.ImageElement:
									chooseImage(ImageElement(element));
									break;
								default:
									break
							}
						} else if(layer.allowBackgroundImage) {
							chooseImage(null);
						}
					}	
					
					break;
			}
			
			/**The FreeFormLine Element need update options once had added to stage.*/
			_card.updateElementsOption();
		}
		
		
		public function chooseImage(element:ImageElement, bSwitch:Boolean = true):void
		{
			_card.chooseImage(element, bSwitch);
		}
		
		public function stage_mouseUpHandler(evt:MouseEvent):void
		{
			mouseDown = false;
			
			if (currentToolType != ToolType.FreeFormLine)
				finalizeMode(true);
			
			stage.removeEventListener(MouseEvent.MOUSE_UP, stage_mouseUpHandler);
			
			_card.updateElementsOption();
			
			if (currentToolType != ToolType.None && currentToolType != ToolType.FreeFormLine)
				finalizeMode(true);
			if (currentToolType == ToolType.None)
				updateCursor();
		}
		
		protected function cutHandler(e:Event):void {
			if(!_active)
				return;
			
			ClipboardManager.value = Globals.designoutputCard.card.getSelectedItemsXML();
			deleteSelectElements();
		}
		
		protected function copyHandler(e:Event):void {
			if(!_active)
				return;
			
			ClipboardManager.value = Globals.designoutputCard.card.getSelectedItemsXML();
		}
		
		protected function pasteHandler(e:Event):void {
			if(!_active)
				return;
			
			var value:Object = ClipboardManager.value;
			if(value is XML)
				pasteItemsXML((value as XML).*);
		}
		
		public function pasteItemsXML(itemsXML:XMLList):void {
			if(!layer)
				return;
			
			var newElements:Array = layer.pasteElementsXML(itemsXML);
			
			dropSelItems();
			
			for each(var element:BaseElement in newElements)
				addSelItem(element);
		}
		
		private function updateEditor():void {
			if(_currentEditor != null)
				_currentEditor.setElements([]);

			_currentEditor = getEditorForSelection();
			
			if(_currentEditor != null)
				_transformBox.setElements(_card.getSelectItems());
		}
		
		private function getEditorForSelection():BaseEditor {
			return _transformBox;
		}
		
		private function deleteSelectElements():void {
			_card.deleteSelectElements();
			updateEditor();
		}
		
		private function dropSelItems():void {
			_card.dropSelItems();
			updateEditor();
		}
		
		private function addSelItem(element:BaseElement):void {
			_card.addSelItem(element);
			updateEditor();
		}
		
		private function dropSelItem(element:BaseElement):void {
			_card.dropSelItem(element);
			updateEditor();
		}
		
		public function keyDownHandler(event:KeyboardEvent):void
		{
			if(event.target != this)
				return;
			
			var keyCode:uint = event.keyCode;
			switch (keyCode)
			{
				case Keyboard.DELETE:
				case Keyboard.BACKSPACE:
					if(_card.getSelectItems().length > 0)
						deleteSelectElements();
					else
						layer.removeBgImage();
					break;
				case Keyboard.NUMBER_0 :
				case Keyboard.NUMPAD_0 :
					if(event.ctrlKey)
						zoom(100);
					break;
				case Keyboard.SHIFT:
					if (_card.shiftKeyActive)
					{
						_card.shiftKeyActive = false;
						SnapUtils.snapEnabled = true;
						Globals.designoutputCard.command.constrainSetMarked(true);
						this.snapTo();
					}
					break;
				case Keyboard.RIGHT:
				case Keyboard.LEFT:
				case Keyboard.UP:
				case Keyboard.DOWN:
					var dx:Number = (keyCode == Keyboard.LEFT ? -1 : (keyCode == Keyboard.RIGHT ? 1 : 0));
					var dy:Number = (keyCode == Keyboard.UP ? -1 : (keyCode == Keyboard.DOWN ? 1 : 0));
					offsetSelectedItems(dx, dy);
				default:
					break;
			}
			_card.updateElementsOption();
		}
		
		public function snapTo():void
		{
			layerMouseMove();
		}
		
		
		public function keyUpHandler(event:KeyboardEvent):void
		{
			var keyCode:uint = event.keyCode;
			switch (keyCode)
			{
				case Keyboard.SHIFT:
					_card.shiftKeyActive=true;
					SnapUtils.snapEnabled = false;
					Globals.designoutputCard.command.constrainSetMarked(false);
					this.snapTo();
					break;
				default:
					break;
			}
		}
		
		
		/**
		 * Update the mouse cursor shape.
		 * <BR><strong>Note:</strong>This function only change the shape of cursor, will not affect others.
		 */
		private function updateCursor():void
		{
			var typeOnPress:String;
			var arr:Array;
			
			arr = _card.getSelectItems();
			typeOnPress = currentToolType;
			
			var type:String = getTypeFromCursor();
			if (this.mouseDown)
			{
				switch (typeOnPress)
				{
					case ToolType.Rectangle:
					case ToolType.RoundRectangle:
					case ToolType.Ellipse:
					case ToolType.StarPolygon:
					case ToolType.FreeFormLine:
					case ToolType.Image:
					case ToolType.Line:
					case ToolType.Text:
						typeOnPress=ToolType.CurrCords;
						break;
				}
				if (this.mouseOver)
				{
					if (typeOnPress == ToolType.Layer)
					{
						typeOnPress=ToolType.SelectionMove;
					}
				}
				Globals.cursorManager.setCursor(typeOnPress);
				
			}
			else if (this.mouseOver)
			{
				if (currentToolType == ToolType.FreeFormLine)
				{
					type=ToolType.CurrCords;
				}
				else if (type == ToolType.Layer)
				{
					type=ToolType.SelectionMove;
				}
				Globals.cursorManager.setCursor(type);
			}
		}
		
		public function offsetSelectedItems(dx:Number, dy:Number):void
		{
			_transformBox.move(dx, dy);			
			_card.setPendingChanges();
		}
			
		/**
		 * Called in Card::setToolType, set the current tool type or command
		 */
		public function setTool(val:String):void
		{
			currentToolType = val;
		}
		
		public function getTool():String
		{
			return currentToolType;
		}
		
		private function addBaseRectElement(elementType:String):BaseRectElement
		{
			var nNewX:Number = layer.mouseX;
			var nNewY:Number = layer.mouseY;
			if (SnapUtils.snapEnabled)
			{
				var p:Point = SnapUtils.getSnapRect(_lastX, _lastY, layer.wrapX(layer.mouseX), layer.wrapY(layer.mouseY));
				nNewX = p.x;
				nNewY = p.y;
			}
			var element:BaseRectElement = BaseRectElement(layer.createElement(elementType));
			var nX:Number = layer.wrapX(Math.min(_lastX, nNewX));
			var nY:Number = layer.wrapY(Math.min(_lastY, nNewY));
			var nW:Number = layer.wrapX(nX + Math.abs(layer.wrapX(_lastX) - layer.wrapX(nNewX))) - nX;
			var nH:Number = layer.wrapY(nY + Math.abs(layer.wrapY(_lastY) - layer.wrapY(nNewY))) - nY;
			var bText:Boolean = elementType != ElementType.ImageElement;
			nX = layer.wrapX(layer.wrapX(nX + nW) - nW);
			nY = layer.wrapY(layer.wrapY(nY + nH) - nH);
			element.x = nX;
			element.y = nY;
			element.width = layer.wrapX(nX + nW) - nX;
			element.height = layer.wrapY(nY + nH) - nY;
			element.validate();
			dropSelItems();
			addSelItem(element);
			return element;
		}
		
		private function addTextElement(elementType:String):TextElement
		{
			var element:TextElement = TextElement(addBaseRectElement(elementType));
			_layerHolder.mouseChildren = true;
			element.editable = true;
			element.validate();
			return element;
		}
		
		private function addRectElement(elementType:String):RectElement
		{
			var element:RectElement = RectElement(addBaseRectElement(elementType));
			element.validate();
			return element;
		}
		
		private function addImageElement(elementType:String):ImageElement
		{
			var element:ImageElement = ImageElement(addBaseRectElement(elementType));
			element.validate();
			return element;
		}
		
		private function addRoundRectElement(elementType:String):RoundRectElement
		{
			var element:RoundRectElement = RoundRectElement(addBaseRectElement(elementType));
			element.validate();
			return element;
		}
		
		private function addEllipseElement(elementType:String):EllipseElement
		{
			var element:EllipseElement = EllipseElement(addBaseRectElement(elementType));
			element.validate();
			return element;
		}
		
		private function addStarElement(elementType:String):StarElement
		{
			var element:StarElement = StarElement(addBaseRectElement(elementType));
			element.validate();
			return element;
		}
		
		private function addPolyLineElement(elementType:String):PolyLineElement
		{
			if (_drawingPoints.length < 0)
				return null;
			var element:PolyLineElement = PolyLineElement(addBaseRectElement(elementType));
			var nMinX:Number = _drawingPoints[0].x;
			var nMinY:Number = _drawingPoints[0].y;
			for (var i:int = 0; i < _drawingPoints.length; i++)
			{
				if (nMinX > _drawingPoints[i].x)
					nMinX = _drawingPoints[i].x;
				if (nMinY > _drawingPoints[i].y)
					nMinY = _drawingPoints[i].y;
			}
			element.x = nMinX;
			element.y = nMinY;
			element.setPoints(_drawingPoints);
			_drawingPoints.splice(0);
			element.updateByShape();
			element.validate();
			return element;
		}
		
		private function addLineElement(elementType:String):LineElement
		{
			dropSelItems();
			var nNewX:Number = layer.mouseX;
			var nNewY:Number = layer.mouseY;
			
			if (SnapUtils.snapEnabled)
			{
				var point:Point = SnapUtils.getSnapLine(_lastX, _lastY, layer.mouseX, layer.mouseY);
				nNewX = point.x;
				nNewY = point.y;
			}

			var element:LineElement = LineElement(layer.createElement(elementType));
			addSelItem(element);
			element.x = _lastX;
			element.y = _lastY;
			element.width = Math.abs(nNewX - _lastX);
			element.height = Math.abs(nNewY - _lastY);
			
			if(nNewX - _lastX < 0)
				element.skewY = -180;
			if(nNewY - _lastY < 0)
				element.skewX = -180;
			
			element.validate();
			return element;
		}
		
		public function selectItems(x1:Number, y1:Number, x2:Number, y2:Number):void
		{
			var topLeft:Point = layer.localToGlobal(new Point(x1, y1));
			var bottomRight:Point = layer.localToGlobal(new Point(x2, y2));
			
			var x:Number = Math.min(topLeft.x, bottomRight.x);
			var y:Number = Math.min(topLeft.y, bottomRight.y);
			var w:Number = Math.abs(bottomRight.x - topLeft.x);
			var h:Number = Math.abs(bottomRight.y - topLeft.y);

			//Create the selection rectangle
			var rectangle:Rectangle = new Rectangle(x, y, w, h);			
			for (var i:Number = 0; i < layer.numElements; i++)
			{
				var elem:BaseElement = layer.getElementAt(i);
				if (HitTestUtils.hitTestRectangle(elem, rectangle))
					addSelItem(elem);
			}
		}
		
		
		public function finalizeMode(bSuccess:Boolean):void
		{
			layer.overlay.graphics.clear();
			
			if (this.currentToolType == ToolType.None)
				return;
			
			if (bSuccess)
			{
				switch (this.currentToolType)
				{
					case ToolType.Layer:
						selectItems(layer.wrapX(_lastX), layer.wrapY(_lastY), layer.wrapX(layer.mouseX), layer.wrapY(layer.mouseY));
						break;
					case ToolType.Rectangle:
						var rectElement:RectElement = addRectElement(ElementType.RectangleElement);
						layer.addElement(rectElement);
						break;
					case ToolType.RoundRectangle:
						var roundRectElement:RoundRectElement = addRoundRectElement(ElementType.RoundRectangleElement);
						layer.addElement(roundRectElement);
						break;
					case ToolType.Ellipse:
						var ellipse:EllipseElement = addEllipseElement(ElementType.EllipseElement);
						layer.addElement(ellipse);
						break;
					case ToolType.StarPolygon:
						var starElement:StarElement = addStarElement(ElementType.StarElement);
						layer.addElement(starElement);
						break;
					case ToolType.FreeFormLine:
						var freeFormLineElement:PolyLineElement = addPolyLineElement(ElementType.PolyLineElement);
						layer.addElement(freeFormLineElement);
						break;
					case ToolType.Line:
						var lineElement:LineElement = addLineElement(ElementType.LineElement);
						if (lineElement)
						{
							layer.addElement(lineElement);
							//(_card.getSelectItems()[0] as BaseElement).normalize();
						}
						break;
					case ToolType.Text:
						var textElement:TextElement = addTextElement(ElementType.TextElement);
						layer.addElement(textElement);
						break;
					case ToolType.Image:
						var imageElement:ImageElement = addImageElement(ElementType.ImageElement);
						chooseImage(imageElement);
						layer.addElement(imageElement);
						break;
					case ToolType.LineHandleLow:
					case ToolType.LineHandleHi:
						_card.getSelectItems()[0].normalize();
						_card.getSelectItems()[0].drawElement();
						break;
					default:
						break;
				}
			}
			else
			{
				switch (this.currentToolType)
				{
					case ToolType.FreeFormLine:
						this._drawingPoints.splice(0);
						break;
				}
			}
			
			Globals.designoutputCard.command.reSetTool();
		}
	}
}